home *** CD-ROM | disk | FTP | other *** search
- Subject: v19i094: Cnews production release, Part17/19
- Newsgroups: comp.sources.unix
- Sender: sources
- Approved: rsalz@uunet.UU.NET
-
- Submitted-by: utzoo!henry
- Posting-number: Volume 19, Issue 94
- Archive-name: cnews2/part17
-
- : ---CUT HERE---
- echo 'relay/sh/postnews':
- sed 's/^X//' >'relay/sh/postnews' <<'!'
- X#! /bin/sh
- X# postnews - post news article
- X
- X# =()<. ${NEWSCONFIG-@<NEWSCONFIG>@}>()=
- X. ${NEWSCONFIG-/usr/lib/news/bin/config}
- X
- XPATH=$NEWSCTL/bin:$NEWSBIN:$NEWSPATH # but do not export it
- Xumask 077 # private
- X
- Xtmp=/tmp/pn$$
- Xterm="rm -f $tmp ; exit 0"
- Xtrap "$term" 0 1 2
- X
- Xif test " $VISUAL" != " "; then
- X edit="$VISUAL"
- Xelif test " $EDITOR" != " "; then
- X edit="$EDITOR"
- Xelse
- X edit=/bin/ed
- Xfi
- X
- Xcase $# in
- X0)
- X if test -r $NEWSCTL/postdefltgroup
- X then
- X defg="`cat $NEWSCTL/postdefltgroup`"
- X dprompt=" [$defg]"
- X else
- X defg=
- X dprompt=
- X fi
- X ans=
- X while test " $ans" = " "
- X do
- X echo "Newsgroup(s)$dprompt? " | tr -d '\012'
- X read ans
- X case "$ans" in
- X '') if test " $defg" != " "
- X then
- X ans="$defg"
- X fi
- X ;;
- X esac
- X done
- X echo "Newsgroups: $ans" >>$tmp
- X ;;
- X
- X1)
- X echo "Newsgroups: $1" >>$tmp
- X ;;
- X
- X*)
- X echo 'Usage: postnews [newsgroups]' >&2
- X exit 2
- X ;;
- Xesac
- X
- Xsubj=
- Xwhile test " $subj" = " "
- Xdo
- X echo 'Subject: ' | tr -d '\012'
- X read subj
- Xdone
- Xecho "Subject: $subj" >>$tmp
- Xif test -r $NEWSCTL/postdefltdist
- Xthen
- X echo "Distribution: `cat $NEWSCTL/postdefltdist`" >>$tmp
- Xfi
- X
- Xecho >>$tmp
- Xecho DELETE THIS LINE "(but DO NOT delete the blank line after the headers above)" >>$tmp
- Xif test -r $NEWSCTL/postdefltdist
- Xthen
- X echo 'DELETE THIS LINE (You may want to change the "Distribution" header)' >>$tmp
- Xfi
- Xecho REPLACE THIS LINE WITH YOUR TEXT >>$tmp
- X
- Xtrap : 2
- X$edit $tmp
- Xtrap "$term" 2
- X
- Xwhile egrep '^(DELETE|REPLACE) THIS LINE' $tmp >/dev/null
- Xdo
- X echo 'This posting does not appear to have been edited properly.'
- X echo 'Abandon it [y] ? ' | tr -d '\012'
- X read ans
- X case "$ans" in
- X ''|y*|Y*)
- X rm -f $tmp
- X exit 0
- X ;;
- X esac
- X
- X echo 'Editing again... Please check it over carefully.'
- X trap : 2
- X $edit $tmp
- X trap "$term" 2
- Xdone
- X
- Xecho 'Posting...'
- Xinews -h <$tmp
- !
- echo 'relay/sh/tear':
- sed 's/^X//' >'relay/sh/tear' <<'!'
- X#! /bin/sh
- X# tear prefix [file...] - tear RFC822 header and body apart
- X# output files are $1hdr and $1body
- XPATH=/bin:/usr/bin; export PATH
- X
- Xcase $# in
- X0)
- X echo "usage: tear prefix [file...]" >&2
- X exit 1
- X ;;
- Xesac
- X
- Xhdr="$1hdr"
- Xbody="$1body"
- Xshift
- X
- X>>$hdr # create files just in case
- X>>$body
- Xcase $# in
- X0) args="-" ;; # awk needs a filename due to cmd. line assignments
- X*) args="$@" ;;
- Xesac
- Xexec awk 'inbody == 0 && $0 ~ /^([ \t]|[^ \t]*:)/ { print >hdr; next }
- X { inbody = 1; print >body }
- X' hdr="$hdr" body="$body" $args
- !
- echo 'relay/sys.c':
- sed 's/^X//' >'relay/sys.c' <<'!'
- X/*
- X * news sys file reading functions
- X */
- X
- X#include <stdio.h>
- X#include <ctype.h>
- X#include <sys/types.h>
- X#include <sys/stat.h>
- X#include "libc.h"
- X#include "fgetmfs.h"
- X#include "news.h"
- X#include "config.h"
- X#include "system.h"
- X
- X#define BTCHDIR "out.going/" /* prefix of relative batch file name */
- X#define BTCHPFX BTCHDIR /* prefix of default batch file name */
- X#define BTCHSFX "/togo" /* suffix of same */
- X#define CMDPFX "uux - -r -z " /* prefix of default command */
- X#define CMDSFX "!rnews" /* suffix of same */
- X
- X/* private */
- Xstatic FILE *fp = NULL; /* stream for ctlfile(filerelname) */
- Xstatic char filerelname[] = "sys"; /* filename relative to $NEWSCTL */
- X
- X/* forward decls */
- XFORWARD char *parsecolon(), *reparse();
- XFORWARD void readsys(), parsesysln(), parse(), parseflags();
- X
- X/* exports */
- Xstruct system *firstsys = NULL; /* cache: 1st sys of in-core sys file */
- Xstruct system *currsys = NULL; /* current system */
- X
- X/* imports */
- Xextern boolean justone;
- Xextern struct system *mysysincache();
- Xextern void rewsys(), remmysys(), freecurrsys();
- X
- Xstruct system *
- Xoursys() /* return our sys entry */
- X{
- X register struct system *sys = mysysincache();
- X static struct system fakesys;
- X
- X if (sys == NULL) {
- X rewsys(fp);
- X while ((sys = nextsys()) != NULL &&
- X !STREQ(sys->sy_name, hostname()))
- X ;
- X if (sys == NULL) {
- X /* no entry: cook one up; no need to malloc members */
- X fakesys.sy_name = hostname();
- X fakesys.sy_excl = NULL;
- X fakesys.sy_ngs = "all";
- X fakesys.sy_distr = "all";
- X fakesys.sy_flags = 0;
- X fakesys.sy_lochops = 0;
- X fakesys.sy_cmd = "";
- X fakesys.sy_next = NULL;
- X sys = &fakesys;
- X }
- X remmysys(sys); /* for future reference */
- X }
- X return sys;
- X}
- X
- X/*
- X * Return the next sys entry, which may span multiple lines.
- X * Returned pointer points at a static struct whose members
- X * point at static storage.
- X *
- X * It would be clearer to rewrite the justone/nextsys/readsys dance
- X * to get rid of justone, but I haven't the energy. Sorry. Beware that
- X * justone is set in either ../libbig/sys.fast.c or ../libsmall/sys.slow.c.
- X */
- Xstruct system *
- Xnextsys()
- X{
- X struct system *retsys;
- X
- X if (firstsys == NULL && fp == NULL)
- X if ((fp = fopenwclex(ctlfile(filerelname), "r")) == NULL)
- X return NULL;
- X if (fp != NULL && firstsys == NULL)
- X readsys();
- X retsys = currsys;
- X if (currsys != NULL)
- X currsys = currsys->sy_next;
- X return retsys;
- X}
- X
- X/*
- X * If justone, read one entry; else read whole sys file (done once only).
- X * Ignores '#' comments and blank lines; uses cfgetms to read possibly-
- X * continued lines of arbitrary length.
- X */
- XSTATIC void
- Xreadsys()
- X{
- X register char *sysline;
- X
- X if (justone)
- X freecurrsys();
- X else
- X rewind(fp);
- X while ((sysline = cfgetms(fp)) != NULL) {
- X if (sysline[0] != '#' && sysline[0] != '\n')
- X parsesysln(sysline);
- X free(sysline);
- X if (justone && firstsys != NULL) { /* parsed an entry */
- X firstsys = NULL;
- X return;
- X }
- X }
- X (void) nfclose(fp);
- X fp = NULL;
- X rewsys(fp);
- X}
- X
- Xstatic char *curr, *next; /* parsing state */
- X
- X/*
- X * Parse (and modify) sysline into *currsys, which is malloced here
- X * and freed iff "justone", in readsys(), see freecursys().
- X *
- X * Side-effect: sysline has a trailing newline removed.
- X */
- XSTATIC void
- Xparsesysln(sysline)
- Xregister char *sysline;
- X{
- X register struct system *sysp =(struct system *)nemalloc(sizeof *sysp);
- X char *flagstring;
- X
- X trim(sysline);
- X next = sysline;
- X parse(&sysp->sy_name);
- X parse(&sysp->sy_ngs);
- X parse(&flagstring);
- X parse(&sysp->sy_cmd);
- X /* could check for extra fields here */
- X
- X parseflags(flagstring, sysp);
- X free(flagstring); /* malloced by parse */
- X sysp->sy_next = NULL;
- X
- X /* reparse for embedded slashes */
- X sysp->sy_excl = reparse(sysp->sy_name, '/');
- X sysp->sy_distr = reparse(sysp->sy_ngs, '/');
- X if (sysp->sy_distr == NULL) /* default distr is ngs... */
- X sysp->sy_distr = sysp->sy_ngs;
- X
- X sysdeflt(sysp); /* fill in any defaults */
- X
- X /* stash *sysp away on the tail of the current list of systems */
- X if (firstsys == NULL)
- X firstsys = sysp;
- X else
- X currsys->sy_next = sysp;
- X currsys = sysp;
- X}
- X
- X/*
- X * fill in defaults in sysp.
- X *
- X * expand a name of "ME" to hostname().
- X * If an empty batch file name was given, supply a default
- X * ($NEWSARTS/BTCHPFX system BTCHSFX).
- X * Prepend $NEWSARTS/BTCHDIR to relative file names.
- X * If an empty command was given, supply a default (uux - -r -z system!rnews).
- X * (This *is* yucky and uucp-version-dependent.)
- X */
- Xvoid
- Xsysdeflt(sysp)
- Xregister struct system *sysp;
- X{
- X if (STREQ(sysp->sy_name, "ME")) {
- X free(sysp->sy_name); /* malloced by parse */
- X sysp->sy_name = strsave(hostname());
- X }
- X if (sysp->sy_flags&FLG_BATCH && sysp->sy_cmd[0] == '\0') {
- X register char *deffile = nemalloc((unsigned) STRLEN(BTCHPFX) +
- X strlen(sysp->sy_name) + STRLEN(BTCHSFX) + 1);
- X
- X (void) strcpy(deffile, BTCHPFX);
- X (void) strcat(deffile, sysp->sy_name);
- X (void) strcat(deffile, BTCHSFX);
- X free(sysp->sy_cmd); /* malloced by parse */
- X sysp->sy_cmd = strsave(fullartfile(deffile));
- X free(deffile);
- X }
- X if (sysp->sy_flags&FLG_BATCH && sysp->sy_cmd[0] != FNDELIM) {
- X register char *absfile = nemalloc((unsigned) STRLEN(BTCHDIR) +
- X strlen(sysp->sy_cmd) + 1);
- X
- X (void) strcpy(absfile, BTCHDIR);
- X (void) strcat(absfile, sysp->sy_cmd);
- X free(sysp->sy_cmd); /* malloced by parse */
- X sysp->sy_cmd = strsave(artfile(absfile));
- X free(absfile);
- X }
- X if (!(sysp->sy_flags&FLG_BATCH) && sysp->sy_cmd[0] == '\0') {
- X free(sysp->sy_cmd); /* malloced by parse */
- X sysp->sy_cmd = nemalloc((unsigned) STRLEN(CMDPFX) +
- X strlen(sysp->sy_name) + STRLEN(CMDSFX) + 1);
- X (void) strcpy(sysp->sy_cmd, CMDPFX);
- X (void) strcat(sysp->sy_cmd, sysp->sy_name);
- X (void) strcat(sysp->sy_cmd, CMDSFX);
- X }
- X}
- X
- X/*
- X * Parse "next" to colon into malloced storage, return its ptr via "into".
- X * *into is freed iff "justone", in readsys(), see freecursys().
- X */
- XSTATIC void
- Xparse(into)
- Xregister char **into;
- X{
- X curr = next;
- X if (curr == NULL)
- X *into = strsave("");
- X else {
- X next = parsecolon(curr);
- X *into = strsave(curr);
- X }
- X}
- X
- XSTATIC char *
- Xparsecolon(line) /* return NULL or ptr. to byte after colon */
- Xchar *line;
- X{
- X register char *colon;
- X
- X INDEX(line, ':', colon);
- X if (colon != NULL)
- X *colon++ = '\0';
- X return colon;
- X}
- X
- X/*
- X * replace "delim" in "field" with a NUL and return the address of the byte
- X * after the NUL (the address of the second subfield), or NULL if no
- X * "delim" was present.
- X */
- XSTATIC char *
- Xreparse(field, delim)
- Xchar *field;
- Xint delim;
- X{
- X register char *delimp = index(field, delim);
- X
- X if (delimp != NULL)
- X *delimp++ = '\0';
- X return delimp;
- X}
- X
- X/*
- X * Parse sys file flags into sysp.
- X */
- XSTATIC void
- Xparseflags(flags, sysp)
- Xregister char *flags;
- Xregister struct system *sysp;
- X{
- X sysp->sy_flags = 0;
- X sysp->sy_lochops = 0; /* default L value */
- X for (; *flags != '\0'; flags++)
- X switch (*flags) {
- X case 'A':
- X errunlock("A news format not supported", "");
- X /* NOTREACHED */
- X case 'B': /* mostly harmless */
- X break;
- X case 'f':
- X sysp->sy_flags |= FLG_BATCH|FLG_SZBATCH;
- X break;
- X case 'F':
- X sysp->sy_flags |= FLG_BATCH;
- X break;
- X case 'I': /* NNTP hook: write msgids, !files */
- X sysp->sy_flags |= FLG_BATCH|FLG_IHAVE;
- X break;
- X case 'L': /* Ln */
- X sysp->sy_flags |= FLG_LOCAL;
- X sysp->sy_lochops = 0;
- X while (isascii(flags[1]) && isdigit(flags[1])) {
- X sysp->sy_lochops *= 10;
- X sysp->sy_lochops += *++flags - '0';
- X }
- X break;
- X case 'm': /* send only moderated groups */
- X sysp->sy_flags |= FLG_MOD;
- X break;
- X case 'N':
- X errunlock(
- X "The N flag is a wasteful old kludge; see the I flag instead.", "");
- X /* NOTREACHED */
- X case 'n': /* NNTP hook: write files+msgids */
- X sysp->sy_flags |= FLG_BATCH|FLG_NBATCH;
- X break;
- X case 'u': /* send only unmoderated groups */
- X sysp->sy_flags |= FLG_UNMOD;
- X break;
- X case 'U': /* mostly harmless */
- X break;
- X case 'H': /* bugger off */
- X case 'S': /* bugger off */
- X case 'M': /* multicast: obs., see batcher */
- X case 'O': /* multicast: obs., see batcher */
- X default:
- X errunlock("unknown sys flag `%s' given", flags);
- X /* NOTREACHED */
- X }
- X}
- X
- Xvoid
- Xrewndsys()
- X{
- X rewsys(fp);
- X}
- !
- echo 'relay/system.h':
- sed 's/^X//' >'relay/system.h' <<'!'
- X/*
- X * parsed form of the "sys" file
- X * Beware that in C++, struct system collides with system(3) in transmit.c
- X * This can be fixed by using "::system(...)" or by renaming struct system.
- X */
- Xstruct system {
- X char *sy_name; /* machine name */
- X char *sy_excl; /* exclusion list of machines */
- X char *sy_ngs; /* newsgroup subscription list */
- X char *sy_distr; /* distribution list */
- X char *sy_cmd; /* command to transmit articles */
- X unsigned sy_lochops; /* flags Ln value: local hops */
- X char sy_flags; /* ornaments, encoded as bits */
- X struct system *sy_next; /* link to next system */
- X};
- X
- X/* sy_flags bits */
- X#define FLG_BATCH (1<<0) /* F: sy_cmd is batch filename */
- X#define FLG_SZBATCH (1<<1) /* f: F, and include byte count */
- X#define FLG_IHAVE (1<<2) /* I: NNTP ihave - F, write msg. ids */
- X#define FLG_LOCAL (1<<3) /* L: send local articles only */
- X#define FLG_MOD (1<<4) /* m: send moderated groups only */
- X#define FLG_UNMOD (1<<5) /* u: send unmoderated groups only */
- X#define FLG_NBATCH (1<<6) /* n: NNTP batch: filename & msg-id */
- X
- X/* imports from system.c */
- Xextern struct system *oursys(), *nextsys();
- Xextern void sysdeflt(), rewndsys();
- !
- echo 'relay/transmit.c':
- sed 's/^X//' >'relay/transmit.c' <<'!'
- X/*
- X * transmit - transmit incoming articles to neighbouring machines
- X */
- X
- X#include <stdio.h>
- X#include <sys/types.h>
- X#include "libc.h"
- X#include "news.h"
- X#include "config.h"
- X#include "headers.h"
- X#include "active.h"
- X#include "article.h"
- X#include "msgs.h"
- X#include "system.h"
- X#include "trbatch.h"
- X#include "transmit.h"
- X
- X/* forwards */
- XFORWARD boolean oktransmit();
- XFORWARD void ejaculate(), trappend();
- X
- X/* private */
- Xstatic boolean debug = NO;
- X
- Xvoid
- Xtransdebug(state)
- Xboolean state;
- X{
- X debug = state;
- X}
- X
- X/*
- X * For each system in "sys" other than this one,
- X * transmit this article when its ng pattern matches
- X * art->h.h_distr (which may be just a copy of art->h.h_ngs).
- X */
- Xvoid
- Xtransmit(art, exclude)
- Xregister struct article *art;
- Xchar *exclude; /* no copy to this site */
- X{
- X register struct system *sys;
- X register int bsysno = 0; /* ordinal # of batch sys entry */
- X
- X rewndsys();
- X if (debug)
- X (void) fprintf(stderr, "just rewound sys file\n");
- X while ((sys = nextsys()) != NULL) {
- X if (debug)
- X (void) fprintf(stderr,
- X "sy_name=%s sy_ngs=%s sy_distr=%s\n",
- X sys->sy_name, sys->sy_ngs, sys->sy_distr);
- X if (oktransmit(art, sys, exclude))
- X ejaculate(art, sys, bsysno);
- X if (sys->sy_flags&FLG_BATCH)
- X ++bsysno;
- X }
- X if (debug)
- X (void) fprintf(stderr, "just finished reading sys file\n");
- X}
- X
- X/*
- X * Is it okay to send the article corresponding to "art" to site "sys",
- X * excluding site "exclude"?
- X *
- X * If L(n) flag is on, must have been posted within n hops of here.
- X * Never send to this site, nor the "exclude" site, nor any site with a host
- X * in sys->sy_excl named in Path:, nor any site named in Path:.
- X *
- X * Newsgroups: must match sys's subscription list.
- X * Distribution: must match sys's distribution list. (RFC 850 is wrong:
- X * Distribution:s are *not* patterns, they are lists. See RFC 1036.)
- X *
- X * If m flag is on, group(s) must be moderated; if u flag is on,
- X * must be unmoderated. (If both are on, act as if neither is on.)
- X */
- XSTATIC boolean
- Xoktransmit(art, sys, exclude)
- Xregister struct article *art;
- Xregister struct system *sys;
- Xchar *exclude; /* no copy to him */
- X{
- X register int flags = sys->sy_flags;
- X register char *site = sys->sy_name;
- X register char *path =
- X canonpath(art->h.h_path, art->h.h_approved, art->h.h_sender);
- X register int result;
- X
- X if (flags&FLG_LOCAL && hopcount(path) > sys->sy_lochops ||
- X STREQ(hostname(), site) ||
- X exclude != NULL && STREQ(exclude, site) || hostin(site, path) ||
- X sys->sy_excl != NULL && anyhostin(sys->sy_excl, path) ||
- X !ngmatch(sys->sy_ngs, art->h.h_ngs) ||
- X !ngmatch(sys->sy_distr, art->h.h_distr))
- X result = NO;
- X else if (flags&(FLG_MOD|FLG_UNMOD)) { /* u, m flag selection */
- X if ((flags&(FLG_MOD|FLG_UNMOD)) == (FLG_MOD|FLG_UNMOD))
- X result = YES; /* too silly */
- X else
- X result = (flags&FLG_MOD? moderated(art->h.h_ngs):
- X !moderated(art->h.h_ngs));
- X } else
- X result = YES;
- X free(path);
- X return result;
- X}
- X
- X/*
- X * Send the article denoted by art to the system denoted by sys.
- X *
- X * When a filename is needed, we use the first one in art->a_files
- X * rather than art->a_tmpf because we want a permanent name, and
- X * translate it to a full path name to avoid ambiguity.
- X *
- X * Side-effect: prints the system name on stdout for logging.
- X */
- XSTATIC void
- Xejaculate(art, sys, bsysno)
- Xregister struct article *art;
- Xregister struct system *sys;
- Xint bsysno;
- X{
- X register char *fullname; /* sometimes is a message-id */
- X
- X if (debug)
- X (void) fprintf(stderr, "transmitting %s to %s\n",
- X art->h.h_msgid, sys->sy_name);
- X (void) printf(" %s", sys->sy_name); /* logging */
- X if (sys->sy_flags&FLG_IHAVE)
- X fullname = art->h.h_msgid;
- X else {
- X register char *filename = first(art->a_files);
- X
- X mkfilenm(filename);
- X fullname = fullartfile(filename);
- X free(filename);
- X }
- X#ifdef PARANOID
- X fullname = strsave(fullname);
- X#endif
- X if (sys->sy_flags&FLG_BATCH)
- X trbatch(art, sys, fullname, bsysno);
- X else
- X trcmd(art, sys, fullname);
- X#ifdef PARANOID
- X free(fullname);
- X#endif
- X}
- X
- X/*
- X * Execute sys->sy_cmd with the current article as stdin
- X * and filename substituted for %s in sys->sy_cmd (if any).
- X *
- X * Search path includes $NEWSCTL/bin and $NEWSBIN/relay.
- X * redirect stdin to prevent consuming my stdin & so cmd's stdin
- X * is filename by default.
- X *
- X * We use strcat instead of sprintf if syscmd contains no %.
- X * this avoids the 128-byte restriction on printf output
- X * (see printf(3) BUGS, at least in V7).
- X */
- Xvoid
- Xtrcmd(art, sys, filename)
- Xstruct article *art;
- Xstruct system *sys;
- Xchar *filename;
- X{
- X register char *cmd;
- X int exitstat;
- X char *syscmd = sys->sy_cmd, *percent;
- X static char *ctlcmd = NULL, *bincmd = NULL;
- X
- X if (ctlcmd == NULL)
- X ctlcmd = strsave(ctlfile("bin"));
- X if (bincmd == NULL)
- X bincmd = strsave(binfile("relay"));
- X cmd = nemalloc((unsigned)(STRLEN("PATH=") + strlen(ctlcmd) +
- X STRLEN(":") + strlen(bincmd) + STRLEN(":") + strlen(newspath()) +
- X STRLEN(" <") + strlen(filename) + STRLEN(" ") +
- X strlen(syscmd) + strlen(filename) + 1));
- X (void) strcpy(cmd, "PATH=");
- X (void) strcat(cmd, ctlcmd);
- X (void) strcat(cmd, ":");
- X (void) strcat(cmd, bincmd);
- X (void) strcat(cmd, ":");
- X (void) strcat(cmd, newspath());
- X (void) strcat(cmd, " <");
- X (void) strcat(cmd, filename);
- X (void) strcat(cmd, " ");
- X percent = index(syscmd, '%');
- X if (percent == NULL)
- X (void) strcat(cmd, syscmd);
- X else {
- X char *pcent2;
- X
- X ++percent;
- X pcent2 = index(percent, '%');
- X if (pcent2 != NULL) {
- X art->a_status |= ST_DROPPED;
- X (void) fprintf(stderr, "%s: `%s' contains two %%'s\n",
- X progname, cmd);
- X } else if (*percent != 's' && *percent != '%') {
- X art->a_status |= ST_DROPPED;
- X (void) fprintf(stderr, "%s: `%s' contains %%%c, not %%s\n",
- X progname, cmd, *percent);
- X } else
- X (void) sprintf(cmd+strlen(cmd), syscmd, filename);
- X }
- X exitstat = system(cmd);
- X if (exitstat != 0) {
- X art->a_status |= ST_DROPPED;
- X (void) fprintf(stderr, "%s: `%s' returned exit status 0%o\n",
- X progname, cmd, exitstat);
- X }
- X free(cmd);
- X}
- X
- X/*
- X * Append "filename" to sys->sy_cmd. bsysno is the ordinal # of this batch
- X * sys line. If bsysno is low enough, use the batchfile cache of batch file
- X * descriptors.
- X */
- Xvoid
- Xtrbatch(art, sys, filename, bsysno)
- Xregister struct article *art;
- Xstruct system *sys;
- Xchar *filename;
- Xregister int bsysno;
- X{
- X register struct batchfile *bf = bfopen(sys->sy_cmd, bsysno);
- X
- X if (bf == NULL || bf->bf_str == NULL)
- X art->a_status |= ST_DROPPED;
- X else {
- X trappend(art, sys, bf, filename);
- X art->a_status |= bffkclose(bsysno);
- X }
- X}
- X
- X/*
- X * write filename, message-id or size on batch file "bf".
- X * under the 'f' flag (FLG_SZBATCH), include the size in bytes of the article
- X * after "name" to assist the C news batcher. under the 'n' flag (FLG_NBATCH),
- X * write the article's message-id. afterward, flush "bf" in case
- X * the machine crashes before the stream is closed.
- X */
- XSTATIC void
- Xtrappend(art, sys, bf, name)
- Xregister struct article *art;
- Xregister struct system *sys;
- Xregister struct batchfile *bf;
- Xchar *name;
- X{
- X if (fputs(name, bf->bf_str) == EOF)
- X fulldisk(art, bf->bf_name);
- X if (sys->sy_flags&FLG_SZBATCH &&
- X fprintf(bf->bf_str, " %ld", art->a_charswritten) == EOF)
- X fulldisk(art, bf->bf_name);
- X if (sys->sy_flags&FLG_NBATCH &&
- X fprintf(bf->bf_str, " %s", art->h.h_msgid) == EOF)
- X fulldisk(art, bf->bf_name);
- X
- X /* don't check putc return value for portability; use ferror */
- X (void) putc('\n', bf->bf_str);
- X if (ferror(bf->bf_str) || bfflush(bf) == EOF)
- X fulldisk(art, bf->bf_name);
- X}
- X
- X/*
- X * really close all the open batch files
- X */
- Xstatust
- Xtrclose()
- X{
- X return bfrealclose();
- X}
- !
- echo 'relay/transmit.h':
- sed 's/^X//' >'relay/transmit.h' <<'!'
- X/* imports from transmit.c */
- Xextern statust trclose();
- Xextern void transdebug(), transmit(), trcmd(), trbatch();
- !
- echo 'relay/trbatch.c':
- sed 's/^X//' >'relay/trbatch.c' <<'!'
- X/*
- X * transmit batch file management
- X */
- X#include <stdio.h>
- X#include <sys/types.h>
- X#include "libc.h"
- X#include "news.h"
- X#include "msgs.h"
- X#include "trbatch.h"
- X
- X/* tunable parameters */
- X#ifndef FLUSHEVERY
- X#define FLUSHEVERY 1 /* fflush batch files every this many lines */
- X#endif /* FLUSHEVERY */
- X#ifndef NOPENBFS
- X#define NOPENBFS 10 /* # batchfiles kept open for batching (arbitrary) */
- X#endif /* NOPENBFS */
- X
- Xstatic struct batchfile batchfile[NOPENBFS]; /* try to keep open always */
- X#define lastbf &batchfile[NOPENBFS-1]
- X/*
- X * More than one pointer in ordtobfs may point at a given batchfile,
- X * to permit sharing of open batch files among multiple sys entries.
- X * ordtobfs[ordinal # of batch sys entry] -> (usually open) batch file,
- X * if the index is in range.
- X */
- Xstatic struct batchfile *ordtobfs[NOPENBFS];
- Xstatic struct batchfile fakebatf; /* for non-cached batch files */
- X
- X/* forwards */
- XFORWARD statust bfclose(), bfrclose();
- XFORWARD struct batchfile *bfincache(), *fakebf();
- X
- X/*
- X * open "name" for appending, for batch sys entry with ordinal # "ord".
- X *
- X * if ord is too big, see if any batchfile has been assigned to "name" yet;
- X * if not, set up a fake batchfile for temporary use. if ord is in range,
- X * ensure that (name, ord) are mapped to a batchfile.
- X *
- X * if an attempt to open the batchfile's stream fails, close a random
- X * batchfile stream and retry the open.
- X */
- Xstruct batchfile *
- Xbfopen(name, ord)
- Xregister char *name;
- Xregister int ord;
- X{
- X register struct batchfile *bf;
- X
- X if (ord >= NOPENBFS) { /* no mapping possible */
- X bf = bfisopen(name);
- X if (bf == NULL)
- X bf = fakebf((FILE *)NULL, name);
- X } else
- X bf = bfincache(name, ord);
- X
- X if (bf->bf_str == NULL)
- X bf->bf_str = fopenclex(name, "a");
- X if (bf->bf_str == NULL) {
- X if (bfrclose() != ST_OKAY)
- X return NULL;
- X bf->bf_str = fopenwclex(name, "a"); /* retry, may bitch */
- X }
- X return bf;
- X}
- X
- X/*
- X * returns a batchfile, never NULL, corresponding to name and ord.
- X * if ord isn't mapped, search the batchfile cache for name;
- X * if missing, initialise batchfile[ord] and map ord to it.
- X * if ord wasn't mapped, but name was in the cache, map ord to the cache hit.
- X */
- XSTATIC struct batchfile *
- Xbfincache(name, ord)
- Xchar *name;
- Xint ord;
- X{
- X register struct batchfile *bf = ordtobfs[ord];
- X
- X if (bf == NULL) {
- X bf = bfisopen(name);
- X if (bf == NULL) {
- X /* establish new mapping for a new file */
- X bf = &batchfile[ord];
- X bf->bf_name = strsave(name);
- X bf->bf_str = NULL; /* paranoia */
- X#ifdef notdef
- X bf->bf_ref = 0;
- X#endif
- X bf->bf_lines = FLUSHEVERY;
- X }
- X ordtobfs[ord] = bf;
- X }
- X /* mapping is now set (ord -> bf) */
- X return bf;
- X}
- X
- Xstatust
- Xbffkclose(ord) /* close ord's batchfile, if fake */
- Xint ord;
- X{
- X register statust status = ST_OKAY;
- X
- X if (ord >= NOPENBFS)
- X status |= bfclose(&fakebatf);
- X return status;
- X}
- X
- XSTATIC statust
- Xbfclose(bf)
- Xregister struct batchfile *bf;
- X{
- X register statust status = ST_OKAY;
- X
- X if (nfclose(bf->bf_str) == EOF)
- X status = prfulldisk(bf->bf_name);
- X bf->bf_str = NULL; /* prevent accidents; mark as closed */
- X return status;
- X}
- X
- XSTATIC struct batchfile *
- Xfakebf(stream, name)
- XFILE *stream;
- Xchar *name;
- X{
- X fakebatf.bf_name = name;
- X fakebatf.bf_str = stream;
- X return &fakebatf;
- X}
- X
- X/*
- X * search the batchfile cache for "name"; return the hit, if any.
- X */
- Xstruct batchfile *
- Xbfisopen(name)
- Xregister char *name;
- X{
- X register struct batchfile *bf;
- X
- X for (bf = batchfile; bf <= lastbf; bf++)
- X if (bf->bf_name != NULL && STREQ(name, bf->bf_name))
- X return bf;
- X return NULL;
- X}
- X
- X/*
- X * a performance hack: only fflush bf->bf_str every FLUSHEVERY calls.
- X */
- Xint
- Xbfflush(bf)
- Xregister struct batchfile *bf;
- X{
- X register int ret = 0;
- X
- X if (--bf->bf_lines <= 0) {
- X bf->bf_lines = FLUSHEVERY;
- X ret = fflush(bf->bf_str);
- X }
- X return ret;
- X}
- X
- XSTATIC statust
- Xbfrclose() /* close a random batchfile */
- X{
- X register struct batchfile *bf;
- X register statust status = ST_OKAY;
- X
- X for (bf = batchfile; bf <= lastbf; bf++)
- X if (bf->bf_str != NULL) {
- X status |= bfclose(bf);
- X break;
- X }
- X return status;
- X}
- X
- Xstatust
- Xbfrealclose() /* close all open batch files */
- X{
- X register struct batchfile *bf;
- X register statust status = ST_OKAY;
- X
- X for (bf = batchfile; bf <= lastbf; bf++) {
- X if (bf->bf_str != NULL) /* batch file stream open */
- X status |= bfclose(bf);
- X nnfree(&bf->bf_name);
- X#ifdef notdef
- X bf->bf_ref = 0;
- X#endif
- X ordtobfs[bf - batchfile] = NULL; /* unmap batch file */
- X }
- X return status;
- X}
- !
- echo 'relay/trbatch.h':
- sed 's/^X//' >'relay/trbatch.h' <<'!'
- X/*
- X * interface to the transmit batch files
- X */
- X
- Xstruct batchfile {
- X#ifdef notdef
- X int bf_ref; /* reference count */
- X#endif
- X FILE *bf_str; /* stream */
- X char *bf_name; /* file name */
- X int bf_lines; /* until fflush */
- X};
- X
- X/* imports from trbatch.c */
- Xextern struct batchfile *bfopen(), *bfisopen();
- Xextern statust bffkclose(), bfrealclose();
- Xextern int bfflush();
- !
- echo 'relay/ihave.not.c':
- sed 's/^X//' >'relay/ihave.not.c' <<'!'
- X/*
- X * Reject the Usenet ihave/sendme control messages.
- X */
- X
- X#include <stdio.h>
- X#include <sys/types.h>
- X
- X#include "news.h"
- X#include "headers.h"
- X#include "article.h"
- X
- Xstatic void
- Xignore(cmd, args)
- Xchar *cmd, *args;
- X{
- X (void) fprintf(stderr, "%s: `%s %s' control ignored\n", progname, cmd, args);
- X}
- X
- X/* ARGSUSED art */
- Xvoid
- Xihave(args, art)
- Xchar *args;
- Xstruct article *art;
- X{
- X ignore("ihave", args);
- X}
- X
- X/* ARGSUSED art */
- Xvoid
- Xsendme(args, art)
- Xchar *args;
- Xstruct article *art;
- X{
- X ignore("sendme", args);
- X}
- !
- echo 'relay/README.relay':
- sed 's/^X//' >'relay/README.relay' <<'!'
- X``yer about to be boarded, ye scurvy network news dogs! har har ...''
- X -- Oliver Wendell Jones, Bloom County Hacker & Cracker
- X
- X``No news is good news.''
- X``When bigger machines are built, netnews will saturate them.''
- X``USENET -- All the news that's fit to `N'.''
- X -- /usr/games/fortune
- X
- X``Net news is the television of computing.''
- X -- Geoff Collyer
- X
- XOn older systems, you will to also install a small program, setnewids,
- Xsetuid-root. If this worries you, read setnewsids.c; all it does is
- Xexecute setgid(), setuid() to the "news" group and user if they exist,
- Xotherwise relaynews's real ids. Setnewsids can be found in ../conf.
- X
- XYou can test relaynews by giving NEWSCTL, NEWSBIN or NEWSARTS
- Xenvironment variables to change the library, binary or spool
- Xdirectories and I encourage this.
- X
- XIf you plan to run rn, you'll need the rn patches to allow Xref: to
- Xwork without Relay-Version:, which has been banished.
- X
- XYou will need to put your site name in /usr/lib/news/mailname (../conf/build
- Xlooks after all this). No upper case letters in your name
- Xplease, there is no call for it and it just looks ugly.
- X
- XYou must only permit relaynews to run on file servers since newsboot clears
- Xall locks in /usr/lib/news.
- X
- XYou'll need compress for compressing or uncompressing batches of news.
- XSee the contact person of your news feed or the moderator of the
- Xnewsgroup comp.sources.unix (try uunet!sources).
- X
- XSee the anews directory for conversion filters from A to B and back.
- X
- XYou'll need to install /usr/lib/newsbin/gngp (see ../misc) before inews
- Xwill work.
- X
- XB-2.11-isms. Your /usr/lib/news/mailpaths file must be updated to
- Xpoint at your nearest backbone site. A 5th sys file field for
- XDistribution: patterns is available (add them in sys after the
- Xsubscription list, separated by "/"), and a 6th field for excluded
- Xhosts is also, separated by "/" from the system name.
- X
- XGood Luck.
- X
- X Geoff Collyer, 8 June 1989
- !
- echo 'rna/README':
- sed 's/^X//' >'rna/README' <<'!'
- XThis is the "Australian readnews", written by Michael Rourke at UNSW.
- XIt's a simple and reasonably well-put-together news reader suitable for
- Xgiving to naive users who aren't going to be reading news much.
- X
- XYou'll need to fiddle defs.h for your machine, then type "make".
- X
- XNote that README.aus assumes you are installing the entire UNSW news
- Xsystem, not just readnews; some of it is inapplicable.
- !
- echo 'rna/README.aus':
- sed 's/^X//' >'rna/README.aus' <<'!'
- XThe files in this distribution are:
- X
- X Makefile
- X README
- X active.c
- X at.h
- X defs.h
- X expire.c
- X funcs.c
- X header.c
- X history.c
- X lib
- X lib/bsearch.c
- X lib/memset.c
- X lib/strpbrk.c
- X lib/tmpfile.c
- X lib/tmpnam.c
- X maketime.c
- X man
- X man/postnews.1
- X man/readnews.1
- X man/uurec.8
- X man/uusend.8
- X mtempnam.c
- X news.help
- X newsrc.c
- X postnews.c
- X readnews.c
- X sample.sys
- X uurec.c
- X uusend.c
- X
- XThis news system is modelled on the USENET news system
- Xby Mark Horton (and others).
- X
- XApart from some minor programs the system has been completely re-written.
- XThe aim of re-writing was to produce a system that was:
- X 1. smaller
- X 2. cleaner
- X 3. faster
- X 4. was compatible at the site <--> site level with USENET
- X 5. had a better user interface ("readnews" and "postnews")
- X
- XThese goals have been met.
- XThe programs "readnews" and "postnews" are 1/3 the previous size, and
- Xdoes not require separate I/D space to run on pdp11/70's.
- XAlso far fewer processes are needed to use "postnews".
- X
- XThis system is compatible with USENET at the site <--> site level, provided
- Xcommunication is done with Version B format messages (the current 'standard').
- XThe messages meet the Standard for the format of ARPA Internet Text messages
- X(RFC 822).
- X
- X"postnews" methods of editing messages is compatible with our local "mail"
- Xprogram (also re-written locally).
- X
- XTo aid someone familiar with USENET to find his/her way around the source:
- X Program changes:
- X "checknews" has become a function of "readnews" (readnews -cC)
- X "postnews" and "inews" are combined into "postnews"
- X "readnews" has the same function (simplified user interface)
- X "expire" has the same function (simplified arguments)
- X "recnews" is not needed
- X "sendnews" has been renamed "uusend" (and simplified)
- X "uurec" has the same function
- X Files:
- X The layout of the news database is the same, except that articles
- X are named #<number> rather than <number>, so that numbers can
- X be a valid newsgroup (like class.6.621).
- X
- X "/usr/lib/news/active" has an extra field - the lowest numbered article
- X present in a newsgroup.
- X "/usr/lib/news/history" has a sightly different format.
- X "/usr/lib/news/sys" is compatible, except that the third field
- X is ignored (always expects format B site); colons are allowed in
- X the last field.
- X
- XTo setup the news system:
- X 1. edit the "defs.h" file and make any changes necessary
- X in particular: MYDOMAIN, MYORG and the paths of SEQ, SYS etc.
- X MANGRPS should not be defined without making suitable
- X modifications to getmangrps() in readnews.c
- X UNSWMAIL is set if you have the version of mail from UNSW,
- X in particular it allows arguments "-s subject -i include_file"
- X to specify the subject, and make include_file available to
- X a ".i" command (like postnews).
- X AUSAM should not be set unless you have the hashed passwd file,
- X and locked file facilities of AUSAM.
- X 1a. edit "Makefile" for the pathnames of LIBDIR, BINDIR and NETDIR.
- X 2. create the account NEWSROOT (defined in defs.h) (this is where
- X the messages are kept).
- X 3. Run the makefile. If you don't have the routines found in
- X lib/* (bsearch, memset etc.) these can be compiled and
- X linked in as required.
- X 4. Create any groups (using "postnews -c 'newgroup <name>'"),
- X that require immediate local posting, otherwise groups will
- X be created automatically when news is received from other sites.
- X Root and NEWSROOT can also mail to non-existent groups, and
- X will be asked whether or not to create the new group.
- X 5. Set up a pseudo user "rnews" to direct received news into
- X "postnews -p" (with uid set to NEWSROOT).
- X How this is done will depend on your network implementation.
- X It may require a deamon emptying a mail box regularly
- X (see rnews.sh in this case).
- X If a mail interface is required, series of messages can be
- X piped into /usr/lib/news/uurec instead.
- X 6. Set up "/usr/lib/news/sys". See sample.sys for an example.
- X Each line in the "sys" file specifies:
- X host name
- X distribution newsgroups
- X (empty field (system assumes type B interchange))
- X the command needed to send the item to the host.
- X Note the current host must have the first two fields also.
- X News transmission can be via "mail" or directly as a
- X network file transfer.
- X 7. Test the system by posting to "to.mysite".
- X 8. Arrange for "expire" to be run periodically (via "cron" or "at").
- X
- XIf you had an existing (old) news system, and wish to transfer the
- Xarticles. The best way to do it is run the command:
- X
- X find oldnewsdir -type f -a -print ^
- X while read F
- X do
- X postnews -p < $F
- X done
- X
- XMichael Rourke
- XUniversity of New South Wales, Australia 13 June 1984
- X(decvax!mulga!michaelr:elecvax)
- X(vax135!mulga!michaelr:elecvax)
- !
- echo 'rna/active.c':
- sed 's/^X//' >'rna/active.c' <<'!'
- X/*
- X * active file handling routines
- X *
- X * format of file:
- X * <groupname> ' ' <5 digit #> ' ' <5 digit #> ' ' flag '\n'
- X * (seq) (low)
- X */
- X
- X#include "defs.h"
- X
- Xstatic char actname[] = ACTIVE;
- Xstatic int lineno;
- Xstatic active *alist;
- X
- X/*
- X * getseq - Get next sequence number for this group
- X * and update active file.
- X * If group missing append to file.
- X */
- Xchar *
- Xgetseq(group)
- Xchar *group;
- X{
- X register FILE *f;
- X register int i;
- X char gbuf[BUFSIZ / 2], dbuf[BUFSIZ / 4], dbuf2[BUFSIZ / 4];
- X extern char *itoa();
- X
- X f = fopenl(actname);
- X lineno = 0;
- X while (getline(f, gbuf, dbuf, dbuf2))
- X if (CMP(gbuf, group) == 0) {
- X i = atoi(dbuf);
- X i++;
- X fseek(f, -12L, 1);
- X (void) fprintf(f, "%05d", i);
- X fclose(f);
- X#if !AUSAM
- X unlock(actname);
- X#endif
- X return itoa(i);
- X }
- X (void) fprintf(f, "%s 00001 00001 y\n", group);
- X fclose(f);
- X#if !AUSAM
- X unlock(actname);
- X#endif
- X return itoa(1);
- X}
- X
- X
- Xstatic
- Xgetline(f, g, d, d2)
- Xregister FILE *f;
- Xchar *g, *d, *d2;
- X{
- X register int c;
- X register char *s;
- X
- X lineno++;
- X s = g;
- X while ((c = getc(f)) != ' ' && c != EOF)
- X *s++ = c;
- X *s = '\0';
- X
- X if (c != EOF) {
- X s = d;
- X while ((c = getc(f)) != EOF && isdigit(c))
- X *s++ = c;
- X *s = '\0';
- X
- X s = d2;
- X if (c == ' ')
- X while ((c = getc(f)) != EOF && isdigit(c))
- X *s++ = c;
- X *s = '\0';
- X
- X if (c == ' ')
- X while ((c = getc(f)) != EOF && c != '\n')
- X ; /* eat flag */
- X }
- X
- X if (c != EOF && (c != '\n' || !*d || !*d2))
- X error("%s: bad format: line %d", actname, lineno);
- X return c != EOF;
- X}
- X
- X
- X/*
- X * build internal active file structure
- X */
- Xactive *
- Xreadactive()
- X{
- X register FILE *f;
- X register active *ap, *last;
- X char gbuf[BUFSIZ / 2], dbuf[BUFSIZ / 4], dbuf2[BUFSIZ / 4];
- X
- X alist = last = NIL(active);
- X f = fopenf(actname, "r");
- X lineno = 0;
- X while (getline(f, gbuf, dbuf, dbuf2)) {
- X ap = NEW(active);
- X ap->a_name = newstr(gbuf);
- X ap->a_seq = atoi(dbuf);
- X ap->a_low = atoi(dbuf2);
- X ap->a_next = NIL(active);
- X if (!alist)
- X alist = ap;
- X else
- X last->a_next = ap;
- X last = ap;
- X }
- X fclose(f);
- X return alist;
- X}
- X
- X
- X/*
- X * return pointer to named group
- X */
- Xactive *
- Xactivep(grp)
- Xregister char *grp;
- X{
- X register active *ap;
- X
- X for (ap = alist; ap; ap = ap->a_next)
- X if (CMP(grp, ap->a_name) == 0)
- X break;
- X return ap;
- X}
- X
- X
- X/*
- X * setlow - set the low number for this group
- X */
- Xsetlow(group, low)
- Xchar *group;
- Xint low;
- X{
- X register FILE *f;
- X char gbuf[BUFSIZ / 2], dbuf[BUFSIZ / 4], dbuf2[BUFSIZ / 4];
- X extern char *itoa();
- X
- X f = fopenl(actname);
- X lineno = 0;
- X while (getline(f, gbuf, dbuf, dbuf2))
- X if (CMP(gbuf, group) == 0) {
- X fseek(f, -6L, 1);
- X (void) fprintf(f, "%05d", low);
- X break;
- X }
- X fclose(f);
- X#if !AUSAM
- X unlock(actname);
- X#endif
- X}
- X
- X
- X
- X/*
- X * initgrp - initialise an entry for this group
- X */
- Xinitgrp(group)
- Xchar *group;
- X{
- X register FILE *f;
- X char gbuf[BUFSIZ / 2], dbuf[BUFSIZ / 4], dbuf2[BUFSIZ / 4];
- X
- X f = fopenl(actname);
- X lineno = 0;
- X while (getline(f, gbuf, dbuf, dbuf2))
- X if (CMP(gbuf, group) == 0) {
- X#if !AUSAM
- X unlock(actname);
- X#endif
- X return;
- X }
- X (void) fprintf(f, "%s 00000 00001\n", group);
- X
- X}
- !
- echo 'rna/at.h':
- sed 's/^X//' >'rna/at.h' <<'!'
- X#define SECINWEEK 604800L
- X#define SECINDAY 86400L
- X#define SECINHOUR 3600L
- X#define SECINMIN 60L
- X#define DAYSTO1983 (10*365 + 3*366)
- X#define MAXTIME 0x7fffffffL
- X
- X/*
- X * frequencies
- X */
- X#define HOURLY 1
- X#define DAILY 2
- X#define WEEKLY 3
- X#define MONTHLY 4
- X#define BOOT 5
- X#define BATCHTIME 6 /* not really a frequency - just looks like one */
- X
- X/*
- X * time types recognised
- X */
- X#define DAYS 0 /* days only */
- X#define TIMES 1 /* days, times */
- X#define FULL 2 /* days, times, frequencies */
- X#define STIMES 3 /* days, times - be silent about errors */
- !
- echo 'rna/defs.h':
- sed 's/^X//' >'rna/defs.h' <<'!'
- X#include <sys/types.h>
- X#include <sys/stat.h>
- X#include <sys/dir.h>
- X#include <stdio.h>
- X#include <ctype.h>
- X#include <time.h>
- X#ifdef USG
- X#include <fcntl.h>
- X#endif
- X#include <signal.h>
- X#include <sgtty.h>
- X#include "at.h"
- X
- X#define NEWSVERSION "B UNSW 1.1 19 Sep 1984"
- X
- X/* Things that very well may require local configuration */
- X
- X#define TIMEZONE "EST" /* name of time zone */
- X
- X#define DFLTSUB "general,general.all" /* default subscription list */
- X#define ADMSUB "general" /* Mandatory subscription list */
- X#define MODGROUPS "mod.all,all.mod,all.announce" /* Moderated groups */
- X#define DFLTGRP "general" /* default newsgroup (for postnews) */
- X/* #define MANGRPS 1 /* if you have mandatory subscriptions
- X tailored per-person (uses
- X getclasses()) */
- X/*#define OZ 1*/ /* if on Australian network, used
- X in readnews to get correct return
- X address */
- X/*#define AUSAM 1*/ /* hashed passwd file, locked files */
- X#if AUSAM
- X#include <passwd.h>
- X#else
- X#include <pwd.h>
- X#endif
- X
- X#ifdef vax
- X/* #define NETPATH 1 /* if you have path finding program
- X /bin/netpath */
- X#endif
- X/*#define UNSWMAIL 1*/ /* if you have UNSW "mail" which
- X allows "-s subject -i include_file"
- X arguments */
- X#define NETID "utzoo"
- X#ifndef NETID
- X#define NETID "utstat" /* else define it here */
- X#endif
- X
- X#ifndef NETID
- X#include <table.h> /* UNSW only */
- X#endif
- X
- X/* #define MC "/usr/bin/p" /* pager */
- X#define UUNAME "/usr/bin/uuname"
- X#define RNEWS "exec rnews" /* rnews for uurec to fork */
- X#define POSTNEWS "/usr/bin/inews"
- X#define CHOWN "/etc/chown" /* pathname of chown command */
- X#define SHELL "/bin/sh" /* if not bourne shell see postnews.c */
- X#define MKDIR "/bin/mkdir"
- X#define MAIL "/bin/mail"
- X#if UNSWMAIL
- X#define FASTMAIL "/bin/mail"
- X#else
- X#define FASTMAIL MAIL
- X#endif
- X
- X#define HELP "/usr/lib/news/help.readnews" /* Help text */
- X#define SEQ "/usr/lib/news/seq" /* Next sequence number */
- X#define SYS "/usr/lib/news/sys" /* System subscription lists */
- X#define ACTIVE "/usr/lib/news/active" /* Active newsgroups */
- X#define HISTORY "/usr/lib/news/history" /* Current articles */
- X
- X#define MYDOMAIN "uucp" /* Local domain */
- X#define MYORG "U of Toronto Zoology" /* My organization */
- X#define NEWSROOT "news" /* news editor */
- X
- X/* Things you might want to change */
- X
- X#define NEWSRC ".newsrc" /* name of .newsrc file */
- X#define PAGESIZE 24 /* lines on screen */
- X#define ARTICLES "articles" /* default place to save articles */
- X#define NEGCHAR '!' /* newsgroup negation character */
- X#define NEGS "!" /* ditto (string) */
- X#define BADGRPCHARS "/#!" /* illegal chars in group name */
- X#define BUFLEN 256 /* standard buffer size */
- X#define ED "/bin/ed" /* default, if $EDITOR not set */
- X
- X/* Things you probably won't want to change */
- X
- X#define NGSEPCHAR ',' /* delimit character in news group line */
- X#define NGSEPS "," /* ditto */
- X#define PSEPS "!" /* separator in Path: */
- X#define PSEPCHAR '!' /* ditto */
- X#define PATHPREF "..!" /* prefix for addresses worked out from Path: */
- X#define TRUE 1
- X#define FALSE 0
- X
- X#ifndef F_SETFD
- X#ifdef F_SETFL
- X#define F_SETFD F_SETFL /* SETFL becomes SETFD (close on exec arg
- X to fcntl) */
- X#endif
- X#endif
- X
- Xtypedef enum booltype { false = 0, true } bool;
- Xtypedef enum applytype { stop, next, nextgroup, searchgroup } applycom;
- Xtypedef applycom (*apcmfunc)();
- Xtypedef enum pheadtype { printing, passing, making } pheadcom;
- X
- X/*
- X * header structure
- X */
- Xtypedef struct header {
- X /* mandatory fields */
- X char *h_relayversion;
- X char *h_postversion;
- X char *h_from;
- X char *h_date;
- X char *h_newsgroups;
- X char *h_subject;
- X char *h_messageid;
- X char *h_path;
- X /* optional fields */
- X char *h_replyto;
- X char *h_sender;
- X char *h_followupto;
- X char *h_datereceived;
- X char *h_expires;
- X char *h_references;
- X char *h_control;
- X char *h_distribution;
- X char *h_organisation;
- X char *h_lines;
- X /* any we don't recognise */
- X char *h_others;
- X} header;
- X
- X/*
- X * internal structure for active file
- X */
- Xtypedef struct active active;
- Xstruct active {
- X char *a_name;
- X short a_seq;
- X short a_low;
- X active *a_next;
- X};
- X
- X/*
- X * internal struct for newsrc file
- X */
- Xtypedef struct newsrc newsrc;
- Xstruct newsrc {
- X char *n_name;
- X bool n_subscribe;
- X short n_last;
- X newsrc *n_next;
- X};
- X
- Xchar *strrchr(), *strchr(), *strcat(), *strcpy(), *strpbrk();
- Xchar *itoa(), *convg(), *ngsquash(), *ttoa(), *mgets(), *rconvg();
- Xchar *newstr(), *newstr2(), *newstr3(), *newstr4(), *newstr5(), *catstr();
- Xchar *catstr2(), *bsearch(), *mtempnam(), *newstr6();
- Xchar *getunique(), *getretaddr(), *getsubject();
- XFILE *fopenl(), *fopenf();
- Xchar *memset(), *myalloc(), *myrealloc();
- Xlong time(), atol(), atot();
- Xint strpcmp();
- Xactive *readactive();
- Xchar *getenv();
- X
- X#define NIL(type) ((type *) 0)
- X#define NEW(type) ((type *) myalloc(sizeof(type)))
- X#define CMP(a, b) (*(a) != *(b) ? *(a) - *(b) : strcmp(a, b))
- X#define CMPN(a, b, n) (*(a) != *(b) ? *(a) - *(b) : strncmp(a, b, n))
- X
- X/* bw 9/15/84 */
- X#define uid_t int
- X#define index strchr
- X#define rindex strrchr
- !
- echo 'rna/funcs.c':
- sed 's/^X//' >'rna/funcs.c' <<'!'
- X#include "defs.h"
- X
- X/*
- X * string handling functions
- X */
- Xchar *
- Xmyalloc(size)
- Xint size;
- X{
- X register char *cp;
- X
- X extern char *malloc();
- X
- X if ((cp = malloc((unsigned) size)) == NIL(char))
- X error("No more memory.");
- X return cp;
- X}
- X
- X
- Xchar *
- Xmyrealloc(ptr, size)
- Xchar *ptr;
- Xint size;
- X{
- X register char *cp;
- X
- X extern char *realloc();
- X
- X if ((cp = realloc(ptr, (unsigned) size)) == NIL(char))
- X error("No more memory.");
- X return cp;
- X}
- X
- X
- Xchar *
- Xnewstr(s)
- Xchar *s;
- X{
- X return strcpy(myalloc(strlen(s) + 1), s);
- X}
- X
- X
- Xchar *
- Xnewstr2(s1, s2)
- Xchar *s1, *s2;
- X{
- X return strcat(strcpy(myalloc(strlen(s1) + strlen(s2) + 1), s1), s2);
- X}
- X
- X
- Xchar *
- Xnewstr3(s1, s2, s3)
- Xchar *s1, *s2, *s3;
- X{
- X return strcat(strcat(strcpy(myalloc(strlen(s1) + strlen(s2) + strlen(s3) +
- X 1), s1), s2), s3);
- X}
- X
- X
- Xchar *
- Xnewstr4(s1, s2, s3, s4)
- Xchar *s1, *s2, *s3, *s4;
- X{
- X return strcat(strcat(strcat(strcpy(myalloc(strlen(s1) + strlen(s2) +
- X strlen(s3) + strlen(s4) + 1), s1), s2), s3), s4);
- X}
- X
- X
- Xchar *
- Xnewstr5(s1, s2, s3, s4, s5)
- Xchar *s1, *s2, *s3, *s4, *s5;
- X{
- X return strcat(strcat(strcat(strcat(strcpy(myalloc(strlen(s1) + strlen(s2) +
- X strlen(s3) + strlen(s4) + strlen(s5) + 1), s1), s2), s3), s4), s5);
- X}
- X
- X
- Xchar *
- Xnewstr6(s1, s2, s3, s4, s5, s6)
- Xchar *s1, *s2, *s3, *s4, *s5, *s6;
- X{
- X return strcat(strcat(strcat(strcat(strcat(strcpy(myalloc(strlen(s1) +
- X strlen(s2) + strlen(s3) + strlen(s4) + strlen(s5) + strlen(s6) + 1),
- X s1), s2), s3), s4), s5), s6);
- X}
- X
- X
- Xchar *
- Xcatstr(old, s)
- Xchar *old, *s;
- X{
- X return strcat(myrealloc(old, strlen(old) + strlen(s) + 1), s);
- X}
- X
- X
- Xchar *
- Xcatstr2(old, s1, s2)
- Xchar *old, *s1, *s2;
- X{
- X return strcat(strcat(myrealloc(old, strlen(old) + strlen(s1) + strlen(s2) +
- X 1), s1), s2);
- X}
- X
- X
- X/*
- X * News group matching.
- X *
- X * nglist is a list of newsgroups.
- X * sublist is a list of subscriptions.
- X * sublist may have "meta newsgroups" in it.
- X * All fields are NGSEPCHAR separated.
- X *
- X * sublist uses "all" like shell uses "*", and "." like shell uses "/"
- X * if subscription X matches Y, it also matches Y.anything
- X */
- Xngmatch(nglist, sublist)
- Xchar *nglist, *sublist;
- X{
- X register char *n, *s, *nd, *sd;
- X register int rc;
- X
- X rc = 0;
- X n = nglist;
- X while (*n && rc == 0) {
- X if (nd = strchr(n, NGSEPCHAR))
- X *nd = '\0';
- X s = sublist;
- X while (*s) {
- X if (sd = strchr(s, NGSEPCHAR))
- X *sd = '\0';
- X if (*s != NEGCHAR)
- X rc |= ptrncmp(s, n);
- X else
- X rc &= ~ptrncmp(s + 1, n);
- X if (sd)
- X *sd = NGSEPCHAR, s = sd + 1;
- X else
- X break;
- X }
- X if (nd)
- X *nd = NGSEPCHAR, n = nd + 1;
- X else
- X break;
- X }
- X return rc;
- X}
- X
- X
- X/*
- X * Compare two newsgroups for equality.
- X * The first one may be a "meta" newsgroup.
- X */
- Xstatic
- Xptrncmp(ng1, ng2)
- Xregister char *ng1, *ng2;
- X{
- X
- X while (1) {
- X if (ng1[0] == 'a' && ng1[1] == 'l' && ng1[2] == 'l' && (ng1[3] ==
- X '\0' || ng1[3] == '.')) {
- X if (ng1[3] == '\0') /* "all" matches anything */
- X return 1;
- X while (*ng2 && *ng2 != '.')
- X ng2++;
- X if (*ng2 != '.') /* "all." doesn't match "xx" */
- X return 0;
- X ng1 += 4, ng2++;
- X continue;
- X }
- X while (*ng1 && *ng1 != '.' && *ng1 == *ng2)
- X ng1++, ng2++;
- X if (*ng1 == '.') {
- X if (*ng2 != '.' && *ng2 != '\0')
- X return 0; /* "."'s don't line up */
- X if (*ng2)
- X ng2++;
- X ng1++; /* "."'s line up - keep going */
- X } else if (*ng1 == '\0')
- X return (*ng2 == '\0' || *ng2 == '.');
- X /* full match or X matching X.thing */
- X else
- X return 0;
- X }
- X /* NOTREACHED */
- X}
- X
- X
- X/*
- X * return new newsgroup composed of only those from 'nglist'
- X * subscribed to by 'sublist'
- X * return NULL for empty list
- X */
- Xchar *
- Xngsquash(nglist, sublist)
- Xregister char *nglist, *sublist;
- X{
- X register char *delim;
- X register char *newg;
- X
- X newg = NIL(char);
- X while (*nglist) {
- X if (delim = strchr(nglist, NGSEPCHAR))
- X *delim = '\0';
- X if (ngmatch(nglist, sublist))
- X newg = (newg ? catstr2(newg, NGSEPS, nglist) : newstr(nglist));
- X if (delim)
- X *delim = NGSEPCHAR, nglist = delim + 1;
- X else
- X break;
- X }
- X return newg;
- X}
- X
- X
- X/*
- X * get unique sequence number from SEQ
- X */
- Xchar *
- Xgetunique()
- X{
- X register long number;
- X register FILE *f;
- X static char buf[12];
- X
- X f = fopenl(SEQ);
- X if (fread(buf, 1, sizeof(buf), f) > 0)
- X number = atol(buf);
- X else
- X number = 1;
- X
- X rewind(f);
- X (void) fprintf(f, "%ld\n", number + 1);
- X fclose(f);
- X#if !AUSAM
- X unlock(SEQ);
- X#endif
- X
- X sprintf(buf, "%ld", number);
- X return buf;
- X}
- X
- X
- X/*
- X * open a locked file (or create) for reading and writing
- X */
- XFILE *
- Xfopenl(fname)
- Xchar *fname;
- X{
- X register FILE *f;
- X#ifdef AUSAM
- X struct stat sbuf;
- X#endif
- X
- X extern uid_t newsuid;
- X
- X if ((f = fopen(fname, "r+")) == NIL(FILE) && (f = fopen(fname, "w+")) ==
- X NIL(FILE))
- X error("Can't open %s", fname);
- X
- X#if AUSAM
- X if (fstat(fileno(f), &sbuf) != 0)
- X error("Can't stat %s", fname);
- X if ((sbuf.st_mode & S_IFMT) != S_IFALK && (chmod(fname, (int) (sbuf.st_mode
- X &~S_IFMT) | S_IFALK) != 0 || chown(fname, (int) newsuid, (int) newsuid) !=
- X 0 || fclose(f) == EOF || (f = fopen(fname, "r+")) == NIL(FILE)))
- X error("Can't create %s", fname);
- X#else
- X chown(fname, (int) newsuid, (int) newsuid);
- X lock(fname);
- X#endif
- X
- X return f;
- X}
- X
- X
- X#if !AUSAM
- X
- X#define LSUFFIX ".lock" /* suffix for lock files */
- X
- Xlock(fname)
- Xchar *fname;
- X{
- X register char *lname;
- X register int i, f;
- X
- X lname = newstr2(fname, LSUFFIX);
- X for (i = 0; i < 10; i++) {
- X if ((f = creat(lname, 0)) != -1) {
- X close(f);
- X free(lname);
- X return;
- X }
- X sleep(2);
- X }
- X error("Can't creat %s after %d tries", lname, i);
- X}
- X
- X
- Xunlock(fname)
- Xchar *fname;
- X{
- X register char *lname;
- X
- X lname = newstr2(fname, LSUFFIX);
- X unlink(lname);
- X free(lname);
- X}
- X
- X
- X#endif
- X
- X/*
- X * open a file
- X */
- XFILE *
- Xfopenf(name, mode)
- Xchar *name, *mode;
- X{
- X register FILE *f;
- X
- X if ((f = fopen(name, mode)) == NIL(FILE))
- X error("Can't %s %s", *mode == 'r' ? "open" : "create", name);
- X return f;
- X}
- X
- X
- X/*
- X * replace all '.''s with '/'
- X */
- Xchar *
- Xconvg(s)
- Xregister char *s;
- X{
- X register char *sav;
- X
- X sav = s;
- X while (s = strchr(s, '.'))
- X *s = '/';
- X return sav;
- X}
- X
- X
- X/*
- X * replace all '/''s with '.'
- X */
- Xchar *
- Xrconvg(s)
- Xregister char *s;
- X{
- X register char *sav;
- X
- X sav = s;
- X while (s = strchr(s, '/'))
- X *s = '.';
- X return sav;
- X}
- X
- X
- X/*
- X * get a line from stdin
- X * trim leading and trailing blanks
- X */
- Xchar *
- Xmgets()
- X{
- X register char *s;
- X static char buf[BUFSIZ];
- X
- X fflush(stdout);
- X if (fgets(buf, sizeof(buf), stdin) == NIL(char)) {
- X (void) printf("\n");
- X return NIL(char);
- X }
- X if (s = strchr(buf, '\n'))
- X while (isspace(*s) && s > buf)
- X *s-- = '\0';
- X else
- X {
- X (void) printf("Input line too long.\n");
- X return NIL(char);
- X }
- X s = buf;
- X while (isspace(*s))
- X s++;
- X return s;
- X}
- X
- X
- Xreadln(f)
- XFILE *f;
- X{
- X register int c;
- X
- X if (feof(f) || ferror(f))
- X return;
- X while ((c = getc(f)) != '\n' && c != EOF)
- X ;
- X}
- X
- X
- X/*
- X * compare string pointers
- X */
- Xstrpcmp(a, b)
- Xchar **a, **b;
- X{
- X return CMP(*a, *b);
- X}
- X
- X
- X/*
- X * apply the given function to each member in the newsgroup
- X */
- X/* VARARGS2 */
- Xapplyng(ng, func, arg1)
- Xregister char *ng;
- Xregister int (*func)();
- Xchar *arg1;
- X{
- X register char *delim;
- X register int err;
- X
- X err = 0;
- X while (*ng) {
- X if (delim = strchr(ng, NGSEPCHAR))
- X *delim = '\0';
- X err += (*func)(ng, arg1);
- X if (delim)
- X *delim = NGSEPCHAR, ng = delim + 1;
- X else
- X break;
- X }
- X return err;
- X}
- X
- X
- X/*
- X * generate a return address
- X */
- Xchar *
- Xgetretaddr(hp)
- Xheader *hp;
- X{
- X register char *ra;
- X
- X extern char *getpath(), *exaddress();
- X#ifdef NETPATH
- X extern char *getnetpath();
- X#endif
- X
- X if (hp->h_replyto)
- X ra = exaddress(hp->h_replyto);
- X else if (hp->h_from)
- X ra = exaddress(hp->h_from);
- X else
- X ra = NIL(char);
- X if (hp->h_path && !ra)
- X ra = getpath(hp->h_path);
- X#ifdef NETPATH
- X if (CMPN(ra, PATHPREF, sizeof(PATHPREF) - 1) == 0)
- X ra = getnetpath(ra);
- X#endif
- X return ra;
- X}
- X
- X
- X/*
- X * try and make a proper address
- X */
- Xchar *
- Xexaddress(addr)
- Xchar *addr;
- X{
- X register char *space, *dot, *at;
- X register char *raddr;
- X
- X raddr = NIL(char);
- X if (space = strchr(addr, ' '))
- X *space = '\0';
- X if (at = strchr(addr, '@')) {
- X *at = '\0';
- X if (dot = strchr(at + 1, '.')) {
- X *dot = '\0';
- X#if OZ
- X if (CMP(dot + 1, MYDOMAIN) == 0)
- X raddr = newstr3(addr, ":", at + 1);
- X else
- X#endif
- X raddr = newstr4(PATHPREF, at + 1, PSEPS, addr);
- X *dot = '.';
- X }
- X *at = '@';
- X }
- X if (space)
- X *space = ' ';
- X return raddr;
- X
- X}
- X
- X
- X/*
- X * return the last two components of the path
- X */
- Xchar *
- Xgetpath(path)
- Xchar *path;
- X{
- X register char *exlast, *ex;
- X register char *raddr;
- X
- X if (exlast = strrchr(path, PSEPCHAR)) {
- X *exlast = '\0';
- X if (ex = strrchr(path, PSEPCHAR))
- X raddr = newstr4(PATHPREF, ex + 1, PSEPS, exlast + 1);
- X else
- X raddr = newstr3(path, PSEPS, exlast + 1);
- X *exlast = PSEPCHAR;
- X } else
- X raddr = NIL(char);
- X return raddr;
- X}
- X
- X
- X#ifdef NETPATH
- X/*
- X * try and work out a path from our "netpath" database
- X */
- Xchar *
- Xgetnetpath(path)
- Xchar *path;
- X{
- X FILE * f;
- X register char *ex1, *ex2, *com, *new;
- X char buf[BUFSIZ];
- X
- X if ((ex1 = strchr(path, PSEPCHAR)) && (ex2 = strchr(ex1 + 1, PSEPCHAR))) {
- X *ex2 = '\0';
- X com = newstr4("exec ", NETPATH, " mulga ", ex1 + 1);
- X if ((f = popen(com, "r")) == NIL(FILE))
- X (void) printf("Couldn't run \"%s\"\n", com);
- X else
- X {
- X fread(buf, sizeof(buf), 1, f);
- X if (pclose(f) != 0) {
- X (void) printf("Error in running \"%s\"\n", com);
- X fflush(stdout);
- X } else if (CMPN(buf, "mulga!", 6) == 0) {
- X if (ex1 = strchr(buf, '\n'))
- X *ex1 = '\0';
- X new = newstr4(buf + 6, PSEPS, ex2 + 1, ":mulga");
- X free(path);
- X path = new;
- X }
- X }
- X free(com);
- X *ex2 = PSEPCHAR;
- X }
- X return path;
- X
- X}
- X
- X
- X#endif
- X
- X/*
- X * remove extra spaces, and insert separators if necessary in
- X * newsgroups specification
- X */
- Xconvgrps(sp)
- Xregister char *sp;
- X{
- X register char *sep;
- X
- X sep = NIL(char);
- X while (*sp) {
- X if (sep)
- X sp++;
- X while (*sp && (isspace(*sp) || *sp == NGSEPCHAR))
- X strcpy(sp, sp + 1);
- X if (sep)
- X *sep = (*sp ? NGSEPCHAR : '\0');
- X while (*sp && !isspace(*sp) && *sp != NGSEPCHAR)
- X sp++;
- X sep = sp;
- X }
- X}
- X
- X
- !
- echo done
-
-
-